/**
 * Copyright (C), 2020, JieYi Software System Co., Ltd.
 * All rights reserved.
 * FileName:       ConsoleInterceptor.java
 *
 * @Description:
 * @author: feiwe
 * Modification History:
 * Date         Author        Version        Discription
 * -------------------------------------------------------
 * 2020/9/30      feiwe                         add
 */


package com.fengwei.interceptor;

import com.fengwei.filter.RepeatedlyReadRequestWrapper;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

public class ConsoleInterceptor implements HandlerInterceptor {
    private final Logger logger = LoggerFactory.getLogger(ConsoleInterceptor.class);

    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    /**
     * 慢服务最大时间单位毫秒
     */
    private static int SLOW_TIME = 500;

    private static AtomicInteger reqCnt = new AtomicInteger(0);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        //静态资源不拦截
//        if (handler instanceof ResourceHttpRequestHandler) {
//            return true;
//        }
        threadLocal.set(System.currentTimeMillis());
        Gson gson = new Gson();
        int connectionSize = reqCnt.incrementAndGet();

        String method = request.getMethod();
        String servletPath = request.getServletPath();
//        logger.debug("method():" + method);
//        logger.debug("servletPath:" + servletPath);

        try {
            if ("OPTIONS".equals(request.getMethod())) {
                //logger.debug("<==[" + servletPath + "], just a OPTIONS, return!==>");
                return true;
            }
            if ("GET".equals(request.getMethod())) {
                //logger.debug("<==[" + servletPath + "], just a GET, return!==>");
                return true;
            }

            /*接着做真正的业务*/
            RepeatedlyReadRequestWrapper requestWrapper;
            String bodyString = null;
            Map jsonObject;
            if (request instanceof RepeatedlyReadRequestWrapper) {
                requestWrapper = (RepeatedlyReadRequestWrapper) request;
                bodyString = RepeatedlyReadRequestWrapper.getBodyString(requestWrapper);

                jsonObject = gson.fromJson(bodyString, Map.class);
                String bizId = (String) jsonObject.get("bizId");
                MDC.put("BIZ_ID", bizId);

                logger.info("<==[" + servletPath + "],start==>");
                logger.debug("bodyString:" + bodyString);
            }
        } catch (Exception e) {
            logger.error("Error:", e);

            throw e;
        } finally {
            reqCnt.decrementAndGet();
        }

        return true;

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        if ("OPTIONS".equals(request.getMethod())) {
            return;
        }
        if ("GET".equals(request.getMethod())) {
            return;
        }

        try {
            // 1、结束时间
            long endTime = System.currentTimeMillis();
            // 2得到线程绑定的局部变量（开始时间）
            long beginTime = threadLocal.get();
            // 3、消耗的时间
            long consumeTime = endTime - beginTime;
            if (consumeTime > SLOW_TIME) {
                // 此处认为处理时间超过500毫秒的请求为慢请求
                logger.warn("<==[" + request.getServletPath() + "] end|time:" + consumeTime + "ms|slow>" + SLOW_TIME + "ms|connectionSize:" + reqCnt
                        + "==>");
            } else {
                logger.warn("<==[" + request.getServletPath() + "] end|time:" + consumeTime + "ms|connectionSize:" + reqCnt + "==>");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            threadLocal.remove();
        }
    }

}
